package com.seanLab.tool;

import com.seanLab.domain.Article;
import com.seanLab.domain.Category;
import com.seanLab.domain.Image;
import com.seanLab.dto.SuggestModelArticleDto;
import com.seanLab.dto.SuggestModelImageDto;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.*;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;


/**
 * Created by ailly on 17-9-23.
 */
public class DataExtractor {
    //从html格式文章抽取：1.文章文本；2.图片列表；3.图片在文章中offset
    private static Map<Integer, Category> categoryMap = null;

    private static int createDirFlag;
    private static String rootSavePath; // 需要填充
    private static String settingFilePath = "settings.properties";
    public static String getArticleContent(String articleHtml) {
        Document article = Jsoup.parse(articleHtml);
        String articleContent = article.body().text();
        return articleContent;
    }

    public  static ArrayList<Image> getImgList(String articleHtml, String articleID) {
        ArrayList<Image> imgList = null;
        //TODO @田添星 抽取，下载，过滤图片列表，返回的imgList的图片都应存放在本地

        //TODO 10.6 更新
        //TODO imgID 使用 uuid命名方式 "image-" + MD5 （与之前约定一致，没有变化）
        //TODO imgURL 使用 uuid.后缀名  格式，例如 image-MD5.jpg（与之前约定一致，没有变化）
        //TODO UUID 例子 tmpArticle_mapFromEditorArticle.setArticleID("article-" + UUID.randomUUID().toString());
        //TODO 新的任务
        //TODO 由于image 与 article类已修改，此函数需要重新调整
        //TODO 考虑把ArticleService 中的 getOffsetFromArticle getCategoryFromArticle getContentFormArticle
        //TODO 都拿到这个类（DataExtractor）中，作为static函数，涉及到小波的两个函数不需要动 (extract开头的)

        String[] s = articleHtml.split("\t");
        if (s.length == 7) {
            String content = getArticleContent(articleHtml);
            List<String> imgID = extractImgID(s[5]);
            List<String> imgURL = extractImgURL(s[5]);
            List<String> imgOrgignalURL = extractImgOriginalURL(s[5]);
            List<String> imgDescription = extractImgDescription(s[5]);
            List<Category> imgCategory = extractImgCategory(s[6]);

            //下载图片
            Properties prop = readProp(settingFilePath);
            String rootSavePath = prop.getProperty("rootSavePath");
            setRootSavePath(rootSavePath);
            downloadImgs(imgURL);

            //过滤图片
            List<Integer> errorCodes = ImgFilter.filtrateImages(imgURL);
            int size = errorCodes.size();
            for(int i = size - 1;i >=0 ;i--){
                if(errorCodes.get(i) != 0){
                    imgID.remove(i);
                    imgURL.remove(i);
                    imgOrgignalURL.remove(i);
                    imgDescription.remove(i);
                    errorCodes.remove(i);
                }
            }

            for(int i = 0;i < imgID.size();i++){
                Image image = new Image();
                image.setImgDescription(imgDescription.get(i));
                image.setImgID(imgID.get(i));
                image.setImgURL(imgURL.get(i));
                image.setImgOriginalURL(imgOrgignalURL.get(i));
                image.setImgCategory(imgCategory);
                image.setImgSource(s[2]);
                int offset = extractOffset(imgURL.get(i), articleHtml);
                String[] context = extractContext(offset, content);
                image.setContextAbove(context[0]);
                image.setContextBelow(context[1]);
                image.setOffset(offset);
                image.setImgType(errorCodes.get(i));
                image.setEsFlag(0);
                image.setDeprecatedFlag(0);
                image.setArticleID(articleID);
                image.setArticleURL(s[4]);
                imgList.add(image);
            }
        } else {
            System.out.println("错误：数据格式异常！数据：" + articleHtml);
        }
        return imgList;
    }

    private static String[] extractContext(int offset, String content) {
//        System.out.println("offset: " + offset);
        int bias = 20;
        offset = content.length() < offset?content.length():offset;
        String[] context = new String[2];
        context[0] = "";
        context[1] = "";

        if(offset == -1){
            return context;
        }

        String front = null;
        if(offset - bias < 0){
            context[0] = content.substring(0, offset);
        }else{
            front = content.substring(0, offset - bias);
            int index1 = front.lastIndexOf("。");
//            System.out.println("offset:" + offset);
//            System.out.println("index1:" + index1);
//            System.out.println("contentLength:" + content.length());
            context[0] = content.substring(index1 + 1, offset);

        }

        if(content.length() - offset - bias < 0){
            context[1] = content.substring(offset);
        }else{
            int index1 = content.indexOf("。", offset + bias);
            if(index1 != -1){
                context[1] = content.substring(offset, index1 + 1);
            }else{
                context[1] = content.substring(offset);
            }
        }
//        System.out.println("context0: " + context[0]);
//        System.out.println("context1: " + context[1] );
//        System.out.println("~~~~~~~~~~~~~~~");
        return context;
    }

    private static int extractOffset(String originalURL, String contentCode){
        String pattern = "<img[^>]*" + originalURL + "[^>]*>";
        String tempCode = contentCode.replaceAll(pattern, "!!!");
        String tempContent = getArticleContent(tempCode);
//        System.out.println("tempContent:" + tempContent);

        int offset = tempContent.indexOf("!!!");
//        System.out.println("offset:" + offset);
        return offset;
    }


    //TODO @田田
//    private List<String> getContextAboveFromArticle(String rawContent) {
//        int bias = 20;
//        List<String> tmpContextAbove = new ArrayList<>();
//        String content = DataExtractor.getArticleContent(rawContent);
//        List<Integer> offsetList = getOffsetFromArticle(rawContent);
//        for(Integer offset:offsetList){
//            offset = content.length() < offset?content.length():offset;
//            String context = "";
//            if(offset != -1){
//                if(offset - bias < 0){
//                    context = content.substring(0, offset);
//                }else{
//                    String front = content.substring(0, offset - bias);
//                    int index1 = front.lastIndexOf("。");
//                    context = content.substring(index1 + 1, offset);
//                }
//            }
//            tmpContextAbove.add(context);
//        }
//
//        return tmpContextAbove;
//    }
    //TODO @田田
//    private List<String> getContextBelowFromArticle(String rawContent) {
//        int bias = 20;
//        List<String> tmpContextBelow = new ArrayList<>();
//        String content = DataExtractor.getArticleContent(rawContent);
//        List<Integer> offsetList = getOffsetFromArticle(rawContent);
//        for(Integer offset:offsetList){
//            offset = content.length() < offset?content.length():offset;
//            String context = "";
//            if(offset != -1){
//                if(content.length() - offset - bias < 0){
//                    context = content.substring(offset);
//                }else{
//                    int index1 = content.indexOf("。", offset + bias);
//                    if(index1 != -1){
//                        context = content.substring(offset, index1 + 1);
//                    }else{
//                        context = content.substring(offset);
//                    }
//                }
//            }
//            tmpContextBelow.add(context);
//        }
//        return tmpContextBelow;
//    }
    //TODO @田田
//    private List<Integer> getOffsetFromArticle(String rawContent) {
//        List<Integer> tmpOffset = new ArrayList<>();
//        List<String> urls = DataExtractor.extractImgURL(rawContent);
//        for(String url:urls){
//            String pattern = "<img[^>]*" + url + "[^>]*>";
//            String tempCode = rawContent.replaceAll(pattern, "!!!");
//            String tempContent = DataExtractor.getArticleContent(tempCode);
//            int offset = tempContent.indexOf("!!!");
//            tmpOffset.add(offset);
//        }
//        return tmpOffset;
//    }


    public static List<List<Category>> getCategoryFromArticle(int[] rawCategory) {
        List<List<Category>> tmpCategory = new ArrayList<List<Category>>();
        //抽取类别信息
        if(categoryMap == null){
            Properties prop = DataExtractor.readProp(settingFilePath);
            String categoryFilePath = prop.getProperty("categoryFilePath");
            Map<Integer, Category> categoryMap = CategoryReader.readCategory(categoryFilePath);
        }

        for(int id:rawCategory){
            List<Category> categoryList = new ArrayList<>();
            Category cat;
            while((cat = categoryMap.get(id)) != null){
                categoryList.add(cat);
                id = cat.getParent_id();
            }
            if(categoryList.size() != 0)
                tmpCategory.add(categoryList);
        }

        return tmpCategory;
    }

    public static String getContentFormArticle(String rawContent){
//        String tmpContent = null;
        String tmpContent = DataExtractor.getArticleContent(rawContent);
        //TODO @田添星 使用DataExtractor抽取文章文本
        //TODO 实现后补全代码
        //TODO String tmpContent = DataExtractor.getArticleContent(rawContent);
        return tmpContent;
    }

    public static Properties readProp(String path){
        Properties prop = new Properties();
        try {
            FileInputStream fis = new FileInputStream(path);
            prop.load(fis);
//            System.out.println("dataFilePath: " + prop.getProperty("dataFilePath"));
//            System.out.println("rootFilePath: " + prop.getProperty("rootSavePath"));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return prop;
    }
    private static void downloadImgs(List<String> imgURL) {
        for(String url:imgURL){
            saveImage(url);
        }
    }

    private static void saveImage(String imgURL) {
        String[] tmp =imgURL.split("/");
        String imgName = tmp[tmp.length - 1];
        saveImage(imgName, imgURL);
    }

    //保存图片
    private static void saveImage(String imgName, String imgURL) {
        byte[] imageData = new byte[1024 * 1000];

        try {
            //url格式判断
            URL url = new URL(imgURL);
            HttpURLConnection conn = null;
            BufferedInputStream bis = null;

            String imgFileName = getSavePath(imgName);
            if(imgFileName == ""){
                System.out.println("图片无后缀：" + imgName);
                return;
            }
            File imgFile = new File(imgFileName);


            if (!imgFile.exists() || imgFile.length() == 138 || imgFile.length() == 0) {
                if(imgFile.length() == 138 || imgFile.length() == 0){
                    imgFile.delete();
                }
                imgFile.createNewFile();

                try {
                    conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setConnectTimeout(10 * 1000);
                    conn.setReadTimeout(50 * 1000);

                    bis = new BufferedInputStream(conn.getInputStream());
                } catch (Exception e) {
                    System.out.println("错误：图片下载失败！ " + imgURL);
                    System.out.println(e);
                    return;
                } finally {
                    // do something
                }

                DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(imgFile)));

                int size = 0;
                while ( (size = bis.read(imageData) )!= -1) {
                    dos.write(imageData, 0 , size);
                }
                dos.flush();
                dos.close();
                bis.close();
                System.out.println("提示：成功保存图片！ " + getSavePath(imgName)  );

            } else {
                System.out.println("提示：图片已存在！" + getSavePath(imgName)  );
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static void setRootSavePath(String rootSavePath) {
        File tmp = new File(rootSavePath);
        if (!tmp.exists()) {
            System.out.println("错误：存储根目录不存在");
            System.exit(1);
        }
        if (rootSavePath.charAt(rootSavePath.length()-1) != '/') {
            rootSavePath = rootSavePath + "/";
        }
        DataExtractor.rootSavePath = rootSavePath;
        //建立目录树
        if(createDirFlag != 1){
            createSaveDirectory();
        }
    }

    //建立目录树
    private static void createSaveDirectory(){
        String firstPrefix = "";
        String secondPrefix = "";
        File root = new File(rootSavePath);
        //检测根目录是否存在
        if (!root.exists()) {
            System.out.println("目录不存在");
            System.exit(1);
        }

        //创建目录树
        char[] vocab = "1234567890abcdefghijklmnopqrstuvwxyz".toCharArray();
        for (char first : vocab) {
            for (char second: vocab) {
                File tmp = new File(rootSavePath + firstPrefix + String.valueOf(first) + "/" + secondPrefix + String.valueOf(second));
                if (!tmp.exists()) {
                    tmp.mkdirs();
                }
            }
        }
        System.out.println("提示：存储目录树建立完毕！");
        createDirFlag = 1;
    }


    private static List<String> extractImgID(String contentStr) {
        List<String> imgIDList = new ArrayList<String>();
        Document article = Jsoup.parse(contentStr);
        Elements img = article.select("img");
        String t = null;
        for (Element s : img) {
            try {
                if (s.hasAttr("src")) {
                    t = s.attr("src");
                    if (t.charAt(0) == '\\') {      //处理元数据中imgURL的转义引号字符
                        //取得图片原始url
                        if (t.split("\\\\\"").length == 0) {
                            imgIDList.add("");
                        } else {
                            String originID = t.split("\\\\\"")[1];
                            String[] tmp = originID.split("/");     //取得图片名字
                            String imgName = tmp[tmp.length - 1];
                            imgIDList.add("image-" + getMD5(imgName));     //计算保存路径
                        }
                    } else {
                        String originID = t;
                        if (originID == null || originID == "") {
                            imgIDList.add("");
                        } else {
                            String[] tmp = originID.split("/");     //取得图片名字
                            String imgName = tmp[tmp.length - 1];
                            imgIDList.add("image-" + getMD5(imgName) );     //计算保存路径
                        }
                    }
                } else {    //没有src属性时，添加空字符串
                    imgIDList.add("");
                }
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("Error in extractImgID: img_info: " + s.toString() + " img.src: " +  s.attr("src") );
            }
        }
        return imgIDList;
    }

    public static List<String> extractImgURL(String contentStr) {
        List<String> imgURLList = new ArrayList<String>();
        Document article = Jsoup.parse(contentStr);
        Elements img = article.select("img");

        for (Element s : img) {
            //统计带src属性img数量
            if (s.hasAttr("src")) {
                String t = s.attr("src");
                if (t.charAt(0) == '\\') {      //处理元数据中imgURL的转义引号字符
                    if (t.split("\\\\\"").length == 0) {
                        imgURLList.add("");
                    } else {
                        String originURL = t.split("\\\\\"")[1];    //取得图片原始url
                        String[] tmp = originURL.split("/");     //取得图片名字
                        String imgName = tmp[tmp.length - 1];

                        imgURLList.add(getSavePath(imgName));     //计算保存路径
                    }
                } else {
                    String originURL = t;
                    if (originURL == null || originURL == "") {
                        imgURLList.add("");
                    } else {
                        String[] tmp = originURL.split("/");     //取得图片名字
                        String imgName = tmp[tmp.length - 1];
                        imgURLList.add(getSavePath(imgName));     //计算保存路径
                    }
                }
            } else {    //没有src属性时，添加空字符串
                imgURLList.add("");
            }
        }
        return imgURLList;
    }

    private static List<String> extractImgOriginalURL(String contentStr) {
        List<String> imgOriginalURLList = new ArrayList<String>();
        Document article = Jsoup.parse(contentStr);
        Elements img = article.select("img");

        for (Element s : img) {
            //统计带src属性img数量
            if (s.hasAttr("src")) {
                String t = s.attr("src");
                if (t.charAt(0) == '\\') {      //处理元数据中imgURL的转义引号字符
                    if (t.split("\\\\\"").length == 0) {
                        imgOriginalURLList.add("");
                    } else {
                        String imgOriginalURL = t.split("\\\\\"")[1];
                        imgOriginalURLList.add(imgOriginalURL);
                    }
                } else {
                    String imgOriginalURL = t;
                    if (imgOriginalURL == null || imgOriginalURL == "") {
                        imgOriginalURLList.add("");
                    } else {
                        imgOriginalURLList.add( imgOriginalURL );     //计算保存路径
                    }

                }
            } else {
                imgOriginalURLList.add("");
            }
        }
        return imgOriginalURLList;
    }

    private static List<String> extractImgDescription(String contentStr) {
        List<String> imgDescriptionList = new ArrayList<String>();
        Document article = Jsoup.parse(contentStr);
        Elements img = article.select("img");

        for (Element s : img) {
            //统计带alt属性img数量
            if (s.hasAttr("alt")) {
                String t = s.attr("alt");
                try {
                    if (t.charAt(0) == '\\') {      //处理元数据中imgDescription的转义引号字符
                        if(t.split("\\\\\"").length != 0) {
                            imgDescriptionList.add(t.split("\\\\\"")[1]);
                        } else {
                            imgDescriptionList.add("");
                        }
                    } else {
                        if (t != "") {
                            imgDescriptionList.add(t);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("error in extractImgDescription: " + t);
                }
            } else {
                imgDescriptionList.add("");
            }
        }
        return imgDescriptionList;
    }


    private static List<Category> extractImgCategory(String s) {
//        System.out.println("catID:" + s);
        s = s.replace("[","");
        s = s.replace("]","");
        String[] idString = s.split(",");
        int[] category = new int[idString.length];
        for (int i = 0; i < category.length; i++) {
            category[i] = Integer.parseInt(idString[i]);
        }

        //如果categoryMap尚未读取，则读取
        if(categoryMap == null){
            Properties prop = DataExtractor.readProp(settingFilePath);
            String categoryFilePath = prop.getProperty("categoryFilePath");
            Map<Integer, Category> categoryMap = CategoryReader.readCategory(categoryFilePath);
        }

        List<Category> result = new ArrayList<>();

        for(int i:category){
            result.add(categoryMap.get(i));
        }
        return result;
    }

    public static String getMD5(String name){
        String code = null;
        try {
            MessageDigest md  = MessageDigest.getInstance("MD5");
            //byte[] cipherData = md.digest(name.getBytes());
            md.update(name.getBytes());
            code = new BigInteger(1, md.digest()).toString(16);
            //code = cipherData.toString();
        } catch (NoSuchAlgorithmException e) {
            System.out.println("错误：MD5摘要生成出错！");
            e.printStackTrace();
        }
        return code;
    }

    //取得图片保存路径
    public static String getSavePath(String imgName){
        if (rootSavePath == null || rootSavePath == "") {
            System.out.println("错误：未设置存储路径！");
            System.exit(1);
        }
        String newName = getMD5(imgName);
        //文章名存储格式
        if (imgName.split("\\.").length > 1) {
            return rootSavePath + "/" + newName.charAt(0) + "/" + newName.charAt(1)+ "/" + newName + "." + imgName.split("\\.")[1];
        } else {
            return rootSavePath + "/" + newName.charAt(0) + "/" + newName.charAt(1)+ "/" + newName;
        }

    }

    public static SuggestModelArticleDto extractModelArticleFromArticle(Article article, List<Image> images) {
        SuggestModelArticleDto suggestModelArticleDto = new SuggestModelArticleDto();
        String code = article.getCode();
        suggestModelArticleDto.setContent(article.getContent());
        suggestModelArticleDto.setTags(article.getTags());
        suggestModelArticleDto.setTitle(article.getTitle());
        List<Integer> offsetList = new ArrayList<>();
        List<String> contextAboveList = new ArrayList<>();
        List<String> contextBelowList = new ArrayList<>();
        for(Image image:images){
            offsetList.add(image.getOffset());
            contextAboveList.add(image.getContextAbove());
            contextBelowList.add(image.getContextBelow());
        }
        List<SuggestModelImageDto> suggestModelImageDtoList = new ArrayList<>();

        //获取对应的图片描述， 首先根据已有的imgID对已经过滤掉的图片进行删除
        List<String> ids = article.getImgID();
        Set<String> idSet = new HashSet<>();
        for(String id:ids){
            idSet.add(id);
        }
        List<String> imgID = extractImgID(code);
        List<String> imgDescription = extractImgDescription(code);
        int size = imgID.size();
        //删掉无效图片
        for(int i = size - 1;i >= 0;i--){
            if(!idSet.contains(imgID.get(i))){
                imgID.remove(i);
                imgDescription.remove(i);
            }
        }

        for(int i = 0;i < offsetList.size();i++){
            try {
                SuggestModelImageDto suggestModelImageDto = new SuggestModelImageDto();
                suggestModelImageDto.setOffset(offsetList.get(i));
                //TODO
                if (imgDescription.size() != 0) {
                    suggestModelImageDto.setDescription(imgDescription.get(i));
                }
                suggestModelImageDto.setContextAbove(contextAboveList.get(i));
                suggestModelImageDto.setContextBelow(contextBelowList.get(i));
                suggestModelImageDtoList.add(suggestModelImageDto);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        suggestModelArticleDto.setSuggestModelImageDtoList(suggestModelImageDtoList);

//        List<SuggestModelImageDto> suggestModelImageDtoList = new ArrayList<>();
//        for(int i = 0;i < imgID.size();i++){
//            String originalURL = imgOrgignalURL.get(i);
//            String description = imgDescription.get(i);
//            int index = content.indexOf(originalURL);
//            SuggestModelImageDto suggestModelImageDto = new SuggestModelImageDto();
//            suggestModelImageDto.setDescription(description);
//            suggestModelImageDto.setOffset(index);
//            suggestModelImageDtoList.add(suggestModelImageDto);
//        }
//        suggestModelArticleDto.setSuggestModelImageDtoList(suggestModelImageDtoList);
        //TODO @田添星 从article中抽取出modelArticle
        return suggestModelArticleDto;
    }

    public static SuggestModelArticleDto extractModelArticleWithoutImgsFromArticle(Article article) {
        SuggestModelArticleDto suggestModelArticleDto = new SuggestModelArticleDto();
        suggestModelArticleDto.setContent(article.getContent());
        suggestModelArticleDto.setTags(article.getTags());
        suggestModelArticleDto.setTitle(article.getTitle());
        return suggestModelArticleDto;
    }

}
